#include "StdAfx.h"
#include "AIEngine.h"

BAA::AIEngine * BAA::AIEngine::pInstance = 0;// initialize pointer

BAA::AIEngine * BAA::AIEngine::getInstance(){
	if( pInstance == NULL ){
		AIEngine::pInstance = new AIEngine();
		return pInstance;
	}else{
		return pInstance;
	}
}

BAA::AIEngine::AIEngine(void)
{
	this->dsengine = new DSEngine();
	this->eq = EventQueue::getInstance();
	currentTime = 0;
}

BAA::AIEngine::~AIEngine(void)
{
	delete dsengine;
	delete eq;
}

//this is responsible for pulling in all the variables and creating an event
//during this time, agentsInvolved is also calculated based on range
void BAA::AIEngine::createEvent( BAA::Agent * source, std::vector<BAA::Agent*> * targets, 
			int urgency, int priority, BAA::Action * action, float range ){

	//agents that are targets are automatically involved
	std::vector<BAA::Agent*> * agentsInvolved = new std::vector<BAA::Agent*>();
	std::vector<BAA::Agent*>::iterator it = targets->begin();
	while ( it != targets->end() ){
		agentsInvolved->push_back( (*it) );
		it++;
	}

	BAA::Vector3 * pos = new BAA::Vector3();
	BAA::Vector3 * dir = new BAA::Vector3();
	pos = source->Properties()->GetTransform()->getPos();
	dir->x = 0.0f;
	dir->y = 0.0f;
	dir->z = 0.0f;
	Transform * t = new Transform( pos, dir );

	//calculate event position against ALL agent positions
	//TODO: this could be improved by having zones
	it = agents.begin();
	while ( it != agents.end() ){
		if( BAA::World::getInstance()->DistanceBetween( source, (*it) ) < range ){
			agentsInvolved->push_back( (*it) );
		}
		it++;
	}

	Event * e = new Event(source, targets, agentsInvolved, urgency, priority, action);
	//now put the event in the outgoing queue
	eq->addOutgoingEvent(e);
}

/*
update() is the entry point into the AI back end
it is reponsible for giving as many agents a turn as possible within timeElapsed time

@param timeElapsed better be in milliseconds!
*/
void BAA::AIEngine::update(float timeElapsed){
	//get next agent to run
	std::pair<BAA::Agent *, float> next;
	bool finished = false;
	FILETIME ft;
    SYSTEMTIME st;
	__int64 timeStamp;
	__int64 currentTime;

	this->currentTime = this->currentTime + timeElapsed;
/*	unsigned ThreadId;
	HANDLE hThread;*/

    GetSystemTime(&st);				// Gets the current system time
    SystemTimeToFileTime(&st, &ft);	// Converts the current system time to file time format
	memcpy(&timeStamp, &ft, sizeof(__int64) );
	timeStamp = timeStamp / 10000;	// Keep it in milliseconds

	while( true ){
		next = dsengine->next(&(this->agents), timeElapsed);

		BAA::GameTime gt;
		gt.current = this->currentTime;
		gt.elasped = timeElapsed;
		next.first->Update( gt );

		GetSystemTime(&st);				// Gets the current system time
		SystemTimeToFileTime(&st, &ft);	// Converts the current system time to file time format
		memcpy(&currentTime, &ft, sizeof(__int64) );
		currentTime = currentTime / 10000;	// Keep it in milliseconds
		if( currentTime - timeStamp > timeElapsed){
			//exit condition
			break;
		}
	}

	//clean up?
}

/*
This function is called by an agent to return any and all events that 
( pertain to it || it requests )
*/
std::vector<BAA::Event *> * BAA::AIEngine::requestEvents(BAA::Agent * requester, float range){
	std::vector<BAA::Event*> * result = new std::vector<BAA::Event*>();
	result->clear();

	//scan both incoming and outgoing events and return all those that has our agent involved
	//an agent is involved by default if they are in range
	std::vector<BAA::Event*>::iterator it = eq->in()->begin();
	while( it != eq->in()->end() ){
		std::vector<BAA::Agent*>::iterator iter = (*it)->getTargets()->begin();
		while( iter != (*it)->getAgentsInvolved()->end() ){
			if( (*iter)->getID() == requester->getID() ){
				//it's a match, add it and move on
				result->push_back( (*it) );
				break;
			}
			iter++;
		}
		it++;
	}

	it = eq->out()->begin();
	while( it != eq->out()->end() ){
		std::vector<BAA::Agent*>::iterator iter = (*it)->getTargets()->begin();
		while( iter != (*it)->getAgentsInvolved()->end() ){
			if( (*iter)->getID() == requester->getID() ){
				//it's a match, add it and move on
				result->push_back( (*it) );
				break;
			}
			iter++;
		}
		it++;
	}

	return result;
}
